package com.dlc.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.app.dto.SkuDto;
import com.dlc.shop.bean.app.vo.ProductVO;
import com.dlc.shop.bean.bo.ProductBO;
import com.dlc.shop.bean.dto.*;
import com.dlc.shop.bean.enums.*;
import com.dlc.shop.bean.event.*;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.param.*;
import com.dlc.shop.bean.vo.SkuComboVO;
import com.dlc.shop.bean.vo.SkuStockVO;
import com.dlc.shop.bean.vo.StockPointSkuVO;
import com.dlc.shop.bean.vo.WarehouseVO;
import com.dlc.shop.common.bean.SysProdConfig;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.CacheNames;
import com.dlc.shop.common.constants.LuaOperateEnum;
import com.dlc.shop.common.constants.StockPointType;
import com.dlc.shop.common.enums.StatusEnum;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ResponseEnum;
import com.dlc.shop.common.util.*;
import com.dlc.shop.dao.*;
import com.dlc.shop.manager.impl.LangManager;
import com.dlc.shop.manager.impl.StockManager;
import com.dlc.shop.service.*;
import com.dlc.shop.util.StockUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.regex.Pattern.compile;

/**
 * @author yami
 */
@Service
@AllArgsConstructor
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    private final ProductMapper productMapper;
    private final ProdLangService prodLangService;
    private final ApplicationContext applicationContext;
    private final BasketService basketService;
    private final SkuService skuService;
    private final BasketMapper basketMapper;
    private final SkuMapper skuMapper;
    private final UserCollectionService userCollectionService;
    private final SkuLangMapper skuLangMapper;
    private final OfflineHandleEventService offlineHandleEventService;
    private final OrderMapper orderMapper;
    private final OrderItemMapper orderItemMapper;
    private final OrderRefundMapper orderRefundMapper;
    private final FlowPageAnalysisMapper flowPageAnalysisMapper;
    private final FlowLogService flowLogService;
    private final FlowUserAnalysisMapper flowUserAnalysisMapper;
    private final ApplicationEventPublisher eventPublisher;
    private final ProdParameterService prodParameterService;
    private final SysConfigService sysConfigService;
    private final ShopDetailService shopDetailService;
    private final ProdExtensionService prodExtensionService;
    private final LangManager langManager;
    private final SkuComboService skuComboService;
    private final StockManager stockManager;
    private final SkuStockService skuStockService;
    private final WarehouseService warehouseService;
    private final StockPointSkuService stockPointSkuService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveProduct(ProductParam productParam) {
        if(Objects.isNull(productParam.getStatus())){
            productParam.setStatus(ProdStatusEnums.NORMAL.getValue());
        }
        checkProdLang(productParam.getProdLangList());
        // 检查一下组合商品情况或者关联组合商品的情况,如果有改变关联,进行下架处理
        checkComboSpuOrRelatedCombo(productParam,null,true);
        Product product = BeanUtil.map(productParam, Product.class);
        // 店铺商品-判断是否需要进行审核
        if (!Objects.equals(product.getShopId(), Constant.PLATFORM_SHOP_ID)) {
            // 判断一下商品审核开关，开着的话默认新发布商品处于待审核状态4
            SysProdConfig sysProdConfig = sysConfigService.getSysConfigObject(Constant.PROD_SWITCH_CONFIG, SysProdConfig.class);
            product.setStatus(BooleanUtil.isTrue(sysProdConfig.getProdAudit()) ? ProdStatusEnums.AUDIT.getValue() : productParam.getStatus());
        } else {
            product.setStatus(productParam.getStatus());
        }
        // 实物商品且不是活动商品，必须要配置物流模板
        boolean deliveryTemplateIsEmpty = Objects.equals(product.getMold(), 0) &&
                !Objects.equals(product.getProdType(), ProdType.PROD_TYPE_ACTIVE.value()) &&
                Objects.isNull(product.getDeliveryTemplateId());
        if (deliveryTemplateIsEmpty) {
            throw new YamiShopBindException("yami.prod.delivery.template.not.null");
        }
        product.setDeliveryMode(Json.toJsonString(productParam.getDeliveryModeVo()));
        product.setUpdateTime(new Date());
        product.setPutawayTime(new Date());
        product.setCreateTime(new Date());
        product.setVersion(0);
        if (Objects.isNull(productParam.getMold()) || !Objects.equals(productParam.getMold(), ProdMoldEnum.VIRTUAL.value())) {
            product.setIsRefund(null);
            product.setWriteOffTime(null);
            product.setWriteOffStart(null);
            product.setWriteOffEnd(null);
            product.setWriteOffNum(null);
            product.setWriteOffMultipleCount(null);
            product.setVirtualRemark(null);
        }
        product.setActivityId(0L);
        productMapper.insert(product);
        // 保存语言表
        productParam.setProdId(product.getProdId());
        Integer prodStock = 0;
        // 保存商品参数
        prodParameterService.saveAndUpdateParameter(productParam.getProdParameterList(), productParam.getProdId());
        if (CollectionUtil.isNotEmpty(product.getSkuList())) {
            List<Sku> skuList = product.getSkuList();
            setSkuName(productParam.getProdLangList(), skuList);
            Long prodId = productParam.getProdId();
            for (Sku sku : skuList) {
                handleSku(sku);
                if (Objects.equals(sku.getStatus(), 1)) {
                    prodStock += sku.getStocks();
                }
                sku.setProdId(prodId);
            }

            List<SkuStockVO> skuStocks = skuService.insertBatchAndLang(skuList, productParam.getShopId(),  productParam.getMold(), product.getStatus(), productParam.getEmployeeMobile(), productParam.getEmployeeId());
            // 数据存储在redis中，所以最后再执行库存插入
            stockManager.skuStock(skuStocks, LuaOperateEnum.SKU_INSERT);
        }
        saveLang(productParam);
        ProdExtension prodExtension = new ProdExtension();
        prodExtension.setProdId(product.getProdId());
        prodExtension.setActualStock(prodStock);
        prodExtension.setStock(prodStock);
        prodExtension.setCommNum(0);
        prodExtensionService.save(prodExtension);
    }

    private void handleSku(Sku sku) {
        double minPrice = 0.01;
        sku.setOriPrice(Objects.isNull(sku.getOriPrice()) ? minPrice : sku.getOriPrice());
        sku.setPrice(Objects.isNull(sku.getPrice()) ? minPrice : sku.getPrice());
        sku.setSupplierPrice(Objects.isNull(sku.getSupplierPrice()) ? minPrice : sku.getSupplierPrice());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProduct(ProductParam productParam, Product dbProduct) {
        // 没有品牌的商品，品牌id设为0
        if (Objects.isNull(productParam.getBrandId())) {
            productParam.setBrandId(0L);
        }
        checkProdLang(productParam.getProdLangList());
        checkComboSpuOrRelatedCombo(productParam,dbProduct,false);
        Product product = BeanUtil.map(productParam, Product.class);
        product.setDeliveryMode(Json.toJsonString(productParam.getDeliveryModeVo()));
        product.setUpdateTime(new Date());

        // 实物商品且不是活动和积分商品，必须要配置物流模板
        boolean deliveryTemplateIsEmpty = Objects.equals(product.getMold(), 0) &&
                !Objects.equals(product.getProdType(), ProdType.PROD_TYPE_ACTIVE.value()) &&
                !Objects.equals(product.getProdType(), ProdType.PROD_TYPE_SCORE.value()) &&
                Objects.isNull(product.getDeliveryTemplateId());
        if (deliveryTemplateIsEmpty) {
            throw new YamiShopBindException("yami.prod.delivery.template.not.null");
        }
        // 店铺商品-判断是否需要进行审核
        handleAuditProds(product, dbProduct);
        productParam.setStatus(product.getStatus());
        List<Long> dbSkuIds = dbProduct.getSkuList().stream().map(Sku::getSkuId).collect(Collectors.toList());
        Map<Long, Sku> dbSkuMap = dbProduct.getSkuList().stream().collect(Collectors.toMap(Sku::getSkuId, dbSku -> dbSku));
        // 将所有该商品的sku标记为已删除状态
        skuMapper.deleteByProdId(product.getProdId());
        // 删除商品对应语言信息列表
        prodLangService.remove(new LambdaQueryWrapper<ProdLang>().eq(ProdLang::getProdId, product.getProdId()));
        // 保存语言表信息
        saveLang(productParam);
        // 保存商品参数
        prodParameterService.saveAndUpdateParameter(productParam.getProdParameterList(), productParam.getProdId());

        // 接口传入sku列表
        List<Sku> skuList = product.getSkuList();

        if (CollectionUtil.isEmpty(skuList)) {
            return;
        }

        // 是否有sku的状态发生变化
        boolean skuStatusChangeFlag = false;

        List<Sku> insertSkuList = new ArrayList<>();
        // 原有sku增加库存的sku列表(不包含新增的sku)
        List<Sku> addStockSkuList = new ArrayList<>();
        // 原有sku减少库存的sku列表(不包含新增的sku)
        List<Sku> reduceStockSkuList = new ArrayList<>();
        setSkuName(productParam.getProdLangList(), skuList);
        skuStatusChangeFlag = updateProdSku(dbProduct, product, dbSkuIds, dbSkuMap, skuList, skuStatusChangeFlag, insertSkuList, addStockSkuList, reduceStockSkuList);

        // 处理sku，保存并更新商品信息
        handleSku(skuList, dbSkuIds, insertSkuList, skuStatusChangeFlag, product);

        // 清除缓存
        removeProdCacheByProdId(dbProduct.getProdId());
    }

    /**
     * 判断商品是否需要进行审核
     * @param product 修改后的商品消息
     * @param dbProduct 修改前的商品消息
     */
    private void handleAuditProds(Product product, Product dbProduct) {
        SysProdConfig sysProdConfig = sysConfigService.getSysConfigObject(Constant.PROD_SWITCH_CONFIG, SysProdConfig.class);
        // 只有商品审核开启并且商品状态为上架状态的商品需要判断，并且不能是积分商品
        if (sysProdConfig.getProdAudit() && dbProduct.getStatus().equals(ProdStatusEnums.NORMAL.getValue()) && !dbProduct.getProdType().equals(ProdType.PROD_TYPE_SCORE.value())) {
            log.info("商品审核开关已开启，判断商品修改数据");
            // 判断商品是否修改了商品名称
            if (product.getProdLangList().size() == dbProduct.getProdLangList().size() && Objects.equals(product.getProdName(), dbProduct.getProdName())) {
                log.info("判断商品是否修改了商品名称、卖点、详情");
                product.getProdLangList().forEach(prodLang -> {
                    dbProduct.getProdLangList().forEach(dbProdLang -> {
                        if (prodLang.getLang().equals(dbProdLang.getLang())) {
                            log.info("语言判断");
                            if (!Objects.equals(prodLang.getProdName(), dbProdLang.getProdName())
                                    || !Objects.equals(prodLang.getBrief(), dbProdLang.getBrief())
                                    || !Objects.equals(prodLang.getContent(), dbProdLang.getContent())) {
                                product.setStatus(ProdStatusEnums.AUDIT.getValue());
                            }
                        }
                    });
                });
            } else {
                product.setStatus(ProdStatusEnums.AUDIT.getValue());
                return;
            }
            // 判断商品是否修改了图片视频
            boolean picflag = Objects.equals(product.getPic(), dbProduct.getPic())
                    && Objects.equals(product.getImgs(), dbProduct.getImgs())
                    && Objects.equals(product.getVideo(), dbProduct.getVideo());
            // 判断商品是否修改了规格（名，值，图片）
            if (product.getSkuList().size() == dbProduct.getSkuList().size() && picflag) {
                log.info("判断商品是否修改了规格（名，值，图片）");
                product.getSkuList().forEach(sku -> {
                    dbProduct.getSkuList().forEach(dbSku -> {
                        if (Objects.equals(sku.getSkuId(), null)){
                            log.info("新增的sku");
                            product.setStatus(ProdStatusEnums.AUDIT.getValue());
                            return;
                        }
                        if (sku.getSkuId().equals(dbSku.getSkuId())) {
                            log.info("语言判断 是否修改了价格");
                            if (!Objects.equals(sku.getSkuName(), dbSku.getSkuName())
                                    || !Objects.equals(sku.getProdName(), dbSku.getProdName())
                                    || !Objects.equals(sku.getProperties(), dbSku.getProperties())
                                    || !Objects.equals(sku.getPic(), dbSku.getPic())
                                    || !Objects.equals(sku.getSupplierPrice(), dbSku.getSupplierPrice())) {
                                product.setStatus(ProdStatusEnums.AUDIT.getValue());
                            }
                        }
                    });
                });
            } else {
                product.setStatus(ProdStatusEnums.AUDIT.getValue());
                return;
            }
            // 判断商品是否修改了参数设置
            checkParamAudit(product);
        }
    }

    /**
     * 判断商品是否修改了参数设置
     * @param product
     */
    private void checkParamAudit(Product product) {
        List<ProdParameter> dbProdParameters = prodParameterService.listParameterAndLang(product.getProdId());
        if (Objects.equals(product.getProdParameterList(), null) && Objects.isNull(dbProdParameters)) {
            log.info("判断商品参数为空，直接返回");
            return;
        }
        boolean parameterFlag = !Objects.equals(product.getProdParameterList(), null) && Objects.isNull(dbProdParameters);
        boolean dbParameterFlag = Objects.nonNull(dbProdParameters) && Objects.equals(product.getProdParameterList(), null);
        if (parameterFlag || dbParameterFlag) {
            log.info("判断商品参数修改过，直接返回");
            product.setStatus(ProdStatusEnums.AUDIT.getValue());
            return;
        }
        if (product.getProdParameterList().size() != dbProdParameters.size()) {
            log.info("商品新增或者删除了参数");
            product.setStatus(ProdStatusEnums.AUDIT.getValue());
        } else {
            product.getProdParameterList().forEach(prodParameter -> {
                dbProdParameters.forEach(dbProdParameter -> {
                    if (Objects.equals(prodParameter.getProdParameterId(), null)) {
                        log.info("新增的参数设置");
                        product.setStatus(ProdStatusEnums.AUDIT.getValue());
                        return;
                    }
                    if (prodParameter.getProdParameterId().equals(dbProdParameter.getProdParameterId())) {
                        log.info("语言判断");
                        if (prodParameter.getProdParameterLangList().size() != dbProdParameter.getProdParameterLangList().size()) {
                            log.info("新增了中文或英文的参数设置");
                            product.setStatus(ProdStatusEnums.AUDIT.getValue());
                            return;
                        }
                        Map<Integer, ProdParameterLang> langMap = prodParameter.getProdParameterLangList().stream().collect(Collectors.toMap(ProdParameterLang::getLang, lang -> lang));
                        Map<Integer, ProdParameterLang> dbLangMap = dbProdParameter.getProdParameterLangList().stream().collect(Collectors.toMap(ProdParameterLang::getLang, lang -> lang));
                        boolean cnflag = !Objects.equals(langMap.get(0) == null ? null : langMap.get(0).getParameterKey() , dbLangMap.get(0) == null ? null : dbLangMap.get(0).getParameterKey())
                                || !Objects.equals(langMap.get(0) == null ? null : langMap.get(0).getParameterValue(), dbLangMap.get(0) == null ? null : dbLangMap.get(0).getParameterValue());
                        boolean enflag = !Objects.equals(langMap.get(1) == null ? null : langMap.get(1).getParameterKey(), dbLangMap.get(1) == null ? null : dbLangMap.get(1).getParameterKey())
                                || !Objects.equals(langMap.get(1) == null ? null : langMap.get(1).getParameterValue(), dbLangMap.get(1) == null ? null : dbLangMap.get(1).getParameterValue());
                        if (cnflag || enflag) {
                            log.info("修改了中文或英文的参数设置");
                            product.setStatus(ProdStatusEnums.AUDIT.getValue());
                        }
                    }
                });
            });
        }
    }

    private void handleSku(List<Sku> skuList, List<Long> dbSkuIds, List<Sku> insertSkuList, boolean skuStatusChangeFlag, Product product){
        List<Long> deleteSkuIds = new ArrayList<>();
        List<Long> existSkuId = skuList.stream().map(Sku::getSkuId).toList();
        for (Long dbSkuId : dbSkuIds) {
            if (!existSkuId.contains(dbSkuId)) {
                deleteSkuIds.add(dbSkuId);
            }
        }

        if (CollUtil.isNotEmpty(insertSkuList) || CollUtil.isNotEmpty(deleteSkuIds) || skuStatusChangeFlag) {
            // 规格发生变化，查看该商品是否参与了套餐活动，正在参与套餐或赠品活动的商品不能修改规格
            GetComboProdCountEvent getComboProdCountEvent = new GetComboProdCountEvent();
            getComboProdCountEvent.setProdId(product.getProdId());
            applicationContext.publishEvent(getComboProdCountEvent);
            if (0 < getComboProdCountEvent.getCount()) {
                throw new YamiShopBindException("yami.product.exception.comboChangeSpec");
            }
            GetGiveawayProdCountEvent getGiveawayProdCountEvent = new GetGiveawayProdCountEvent();
            getGiveawayProdCountEvent.setProdId(product.getProdId());
            getGiveawayProdCountEvent.setGiveawayProdType(2);
            applicationContext.publishEvent(getGiveawayProdCountEvent);
            if (getGiveawayProdCountEvent.getCount() > 0) {
                throw new YamiShopBindException("yami.product.exception.giveawayChangeSpec");
            }
        }

        // 需要删除的skuIds对应的购物车
        deleteShopCart(dbSkuIds, skuList);
        // 更新商品信息
        saveOrUpdate(product);
        // 删除sku关联信息
        applicationContext.publishEvent(new SkuDeleteEvent(deleteSkuIds));
    }

    @Override
    public void updateWaterSaleNum(Integer waterSoldNum, Long prodId) {
        prodExtensionService.updateWaterSoldNum(waterSoldNum, prodId);
        prodExtensionService.removeProdExtensionCache(prodId);
    }

    /**
     * 删除sku时，删除掉关联购物车
     *
     * @param dbSkuIds 数据库sku信息
     * @param skuList  此时修改后的信息
     */
    private void deleteShopCart(List<Long> dbSkuIds, List<Sku> skuList) {
        List<Long> deleteSkuIds = new ArrayList<>();
        List<Long> existSkuId = skuList.stream().map(Sku::getSkuId).toList();
        for (Long dbSkuId : dbSkuIds) {
            if (!existSkuId.contains(dbSkuId)) {
                deleteSkuIds.add(dbSkuId);
            }
        }
        // 如果不为空，则进行删除关联的购物车
//        if (CollectionUtils.isNotEmpty(deleteSkuIds)) {
//            for (Long deleteSkuId : deleteSkuIds) {
//                basketMapper.delete(new LambdaQueryWrapper<Basket>().eq(Basket::getSkuId, deleteSkuId));
//            }
//        }
    }

    /**
     * 这里的缓存 1800秒消失，详情RedisCacheConfig这里的配置
     * 当秒杀的时候，并不更新这里的缓存，所以库存会滞后，但是半个小时后缓存消失，又会重新获取
     *
     * @param prodId
     * @return
     */
    @Override
    @Cacheable(cacheNames = CacheNames.PRODUCT_KEY, key = "#prodId",unless="#result == null")
    public Product getProductByProdId(Long prodId) {
        Product product = productMapper.selectByIdAndLang(prodId);
        if(Objects.isNull(product)){
            return null;
        }
        langManager.getProdAndLang(product);
        return product;
    }

    @Override
    public Product getProductAndLang(Long prodId) {
        ProductServiceImpl productService = (ProductServiceImpl) AopContext.currentProxy();
        Product product = productService.getProductByProdId(prodId);
        if(Objects.isNull(product)){
            return null;
        }
        langManager.handleProdLang(product);
        return product;
    }

    @Override
    public Product getProductInfo(Long prodId) {
        Product product = this.getProductAndLang(prodId);
        ProdExtension prodExtension = prodExtensionService.getByProdId(prodId);
        product.setTotalStocks(prodExtension.getStock());
        product.setWaterSoldNum(prodExtension.getWaterSoldNum());
        product.setSoldNum(prodExtension.getSoldNum());
        return product;
    }

    @Override
    public Product getProductById(Long prodId) {
        return getProductInfo(prodId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeProductByProdId(Long prodId, List<Long> deleteSkuIds) {
        ProductService productService = (ProductService) AopContext.currentProxy();
        Product dbProduct = productService.getProductByProdId(prodId);
        // 将商品的状态变成-1（逻辑删除）
        Product product = new Product();
        product.setProdId(prodId);
        product.setIsTop(0);
        product.setStatus(-1);
        saveOrUpdate(product);
        skuMapper.deleteByProdId(prodId);
        //删除用户收藏中的该商品
        userCollectionService.remove(new LambdaQueryWrapper<UserCollection>()
                .eq(UserCollection::getProdId, prodId));
        // 删除语言表信息
        skuLangMapper.deleteByProdId(prodId);
        // 删除商品参数
        prodParameterService.removeByProdId(prodId);
        // 删除商品时，改变分销设置,团购订单处理。。。
        applicationContext.publishEvent(new ProdChangeEvent(dbProduct));
        // 删除关联的组合商品信息
        if(CollectionUtils.isNotEmpty(deleteSkuIds)) {
            offlineRelatedComboBySpuIds(Collections.singletonList(prodId));
            skuComboService.remove(new LambdaQueryWrapper<SkuCombo>().eq(SkuCombo::getComboProdId, prodId));
            skuComboService.remove(new LambdaQueryWrapper<SkuCombo>().in(SkuCombo::getSkuId, deleteSkuIds));
        }
        // 清除缓存
        removeProdCacheByProdId(prodId);
    }


    @Override
    public void removeProdCacheByProdId(Long prodId) {
        if (Objects.isNull(prodId)) {
            return;
        }
        removeProductCacheByProdIds(Collections.singletonList(prodId));
    }

    @Override
    public void removeProductCacheByProdIds(List<Long> prodIds) {
        if (CollUtil.isEmpty(prodIds)) {
            return;
        }
        List<String> keys = new ArrayList<>();
        for (Long prodId : prodIds) {
            // cacheNames = "product"
            keys.add(CacheNames.PRODUCT_KEY + CacheNames.UNION + prodId);
            // cacheNames = "skuList"
            keys.add(CacheNames.SKU_LIST_KEY + CacheNames.UNION + prodId);
            // cacheNames = "prodExtensionInfo"
            keys.add(CacheNames.PROD_EXTENSION_INFO_KEY + CacheNames.UNION + prodId);
        }
        RedisUtil.del(keys);

    }

    @Override
    public void removeProdExtensionCache(Long prodId) {
        prodExtensionService.removeProdExtensionCache(prodId);
    }

    @Override
    public List<ProdAndSkuListsDto> getProdAndSkuLists(List<Long> prodIds) {
        List<ProdAndSkuListsDto> productList = productMapper.getProdAndSkuLists(prodIds);
        Set<Long> skuIdSet = new HashSet<>();
        for (ProdAndSkuListsDto prodAndSkuListsDto : productList) {
            skuIdSet.addAll(prodAndSkuListsDto.getSkuDtoList().stream().map(SkuDto::getSkuId).toList());
        }
        Map<Long, SkuStockVO> skuStockMap = skuStockService.mapSkuTotalStock(new ArrayList<>(skuIdSet));
        for (ProdAndSkuListsDto prodAndSkuListsDto : productList) {
            for (SkuDto skuDto : prodAndSkuListsDto.getSkuDtoList()) {
                if (!skuStockMap.containsKey(skuDto.getSkuId())) {
                    continue;
                }
                SkuStockVO skuStockVO = skuStockMap.get(skuDto.getSkuId());
                skuDto.setStocks(skuStockVO.getStock());
            }
        }
        return productList;
    }

    @Override
    public int updateProductToGroup(Long groupActivityId, Long prodId) {
        return productMapper.updateProductToGroup(groupActivityId, prodId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OfflineHandleEventItem auditApply(Long eventId, Long prodId, String reapplyReason) {
        // 更新商品为待审核状态
        productMapper.updateToApply(prodId);
        // 更新事件状态
        OfflineHandleEventItem offlineHandleEventItem = offlineHandleEventService.updateToApply(eventId, reapplyReason);
        Product product = new Product();
        product.setProdId(prodId);
        product.setStatus(ProdStatusEnums.PLATFORM_AUDIT.getValue());
        // 商品状态改变时的发送事件
        applicationContext.publishEvent(new ProdChangeStatusEvent(product, product.getStatus()));
        return offlineHandleEventItem;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void prodAudit(OfflineHandleEventAuditParam offlineHandleEventAuditParam, Long sysUserId) {
        // 审核通过,更新商品状态
        Product product = new Product();
        Product dbProduct = this.getProductAndLang(offlineHandleEventAuditParam.getHandleId());
        product.setProdId(offlineHandleEventAuditParam.getHandleId());
        if(Objects.equals(dbProduct.getStatus(), ProdStatusEnums.DELETE.getValue())){
            throw new YamiShopBindException("yami.product.exception.statusChange");
        }
        if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            productMapper.updateToShopOffline(offlineHandleEventAuditParam.getHandleId());
            product.setStatus(ProdStatusEnums.SHOP_OFFLINE.getValue());
        } else if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.DISAGREE_BY_PLATFORM.getValue())) {
            productMapper.updateToOffline(offlineHandleEventAuditParam.getHandleId());
            product.setStatus(ProdStatusEnums.PLATFORM_OFFLINE.getValue());
        }
        // 商品状态改变时的发送事件，让活动下线
        applicationContext.publishEvent(new ProdChangeStatusEvent(product, product.getStatus()));
        offlineHandleEventService.auditOfflineEvent(offlineHandleEventAuditParam, sysUserId);
        //发送商品审核提醒给商家
        NotifyTemplateParam shopParam = new NotifyTemplateParam();
        shopParam.setShopId(dbProduct.getShopId());
        shopParam.setProdId(offlineHandleEventAuditParam.getHandleId());
        shopParam.setProdName(dbProduct.getProdName());
        shopParam.setSendType(SendType.PRODUCT_AUDIT.getValue());
        applicationContext.publishEvent(new SendMessageEvent(shopParam));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OfflineHandleEvent offline(Long prodId, String offlineReason, Long sysUserId) {
        Product product = getById(prodId);

        // 添加下线处理记录
        Date now = new Date();
        OfflineHandleEvent offlineHandleEvent = new OfflineHandleEvent();
        offlineHandleEvent.setHandleType(OfflineHandleEventType.PROD.getValue());
        offlineHandleEvent.setHandleId(product.getProdId());
        offlineHandleEvent.setHandlerId(sysUserId);
        offlineHandleEvent.setOfflineReason(offlineReason);
        offlineHandleEvent.setCreateTime(now);
        offlineHandleEvent.setShopId(product.getShopId());
        offlineHandleEvent.setStatus(OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue());
        offlineHandleEvent.setUpdateTime(now);
        offlineHandleEventService.save(offlineHandleEvent);

        // 更新活动状态为下线
        productMapper.updateToOffline(prodId);
        // 下线关联的组合商品
        offlineRelatedComboBySpuIds(Collections.singletonList(prodId));
        return offlineHandleEvent;
    }

//    @Override
//    public IPage<Product> getPageAngShopName(PageParam<Product> page, ProductParam product) {
//        return productMapper.getPageAndShopName(page, product);
//    }


    @Override
    public List<ProdAnalysisDataParam> getProdTrendAnalysis(ProdAnalysisSurveyParam param) {
        List<ProdAnalysisDataParam> datas = new ArrayList<>();
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        // 商品访客数列表
        List<ProdAnalysisDataParam> prodVisitorList = flowUserAnalysisMapper.countProdVisitorNum(param);
        Map<String, ProdAnalysisDataParam> prodVisitorMap = prodVisitorList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, p -> p));
        //数据统计列表
        List<ProdAnalysisDataParam> flowUserAnalysisList = flowUserAnalysisMapper.analysisSurvey(param);
        Map<String, ProdAnalysisDataParam> flowUserAnalysisMap = flowUserAnalysisList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, p -> p));
        // 新增商品数量列表
        List<ProdAnalysisDataParam> newProdList = productMapper.listNewProdByTime(param);
        Map<String, Long> newProdMap = newProdList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, ProdAnalysisDataParam::getNewProd));
        //订单统计列表
        List<ProdAnalysisDataParam> prodSurveyList = orderMapper.prodSurveyList(param);
        Map<String, ProdAnalysisDataParam> prodSurveyMap = prodSurveyList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, p -> p));
        while (startTime.getTime() <= endTime.getTime()) {
            String date = DateUtils.dateToStrYmd(startTime);
            ProdAnalysisDataParam prodAnalysisDataParam = new ProdAnalysisDataParam();
            prodAnalysisDataParam.setCurrentDay(date);
            if (prodVisitorMap.containsKey(date)) {
                prodAnalysisDataParam.setVisitor(prodVisitorMap.get(date).getVisitor());
            }
            if (flowUserAnalysisMap.containsKey(date)) {
                prodAnalysisDataParam.setVisitedProd(flowUserAnalysisMap.get(date).getVisitedProd());
                prodAnalysisDataParam.setAddCart(flowUserAnalysisMap.get(date).getAddCart());
                prodAnalysisDataParam.setBrowse(flowUserAnalysisMap.get(date).getBrowse());
                prodAnalysisDataParam.setShareVisit(flowUserAnalysisMap.get(date).getShareVisit());
            }
            if (prodSurveyMap.containsKey(date)) {
                prodAnalysisDataParam.setDynamicSale(prodSurveyMap.get(date).getDynamicSale());
                prodAnalysisDataParam.setPayNum(prodSurveyMap.get(date).getPayNum());
                prodAnalysisDataParam.setOrderNum(prodSurveyMap.get(date).getOrderNum());
            }
            startTime = DateUtil.offsetDay(startTime, 1);
            param.setDateTime(endTime);
            // 在架商品数据
            if (newProdMap.containsKey(date)) {
                prodAnalysisDataParam.setNewProd(newProdMap.get(date));
            } else {
                prodAnalysisDataParam.setNewProd(0L);
            }
            datas.add(prodAnalysisDataParam);
        }
        return datas;
    }

    @Override
    public IPage<ProdEffectRespParam> pageProdEffect(PageParam<Product> page, ProdEffectParam param, Integer lang, boolean allProd) {
        // 查询出在架商品
        Integer status = param.getStatus();
        if (Objects.isNull(status)) {
            param.setStatus(0);
        }
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        Set<Long> prodIdSet = getFlowProdId(param.getDateType(), startTime, endTime, param.getShopId());
        IPage<ProdEffectRespParam> pages = new Page<>();
        if (CollUtil.isEmpty(prodIdSet)) {
            return pages;
        }
        List<ProdEffectRespParam> respParams = productMapper.getProdEffectByParam(param, prodIdSet);
        param.setStatus(status);
        List<Long> prodIds = new ArrayList<>();
        prodIds.addAll(prodIdSet);
        List<ProdEffectRespParam> prodFlowList = getProdFlowData(param.getDateType(), prodIds, startTime, endTime);

        List<ProdEffectRespParam> prodOrderList = orderItemMapper.getProdEffectByDateAndProdIds(prodIds, startTime, endTime);

        List<ProdEffectRespParam> prodOrderRefundList = orderRefundMapper.getProdEffectByDateAndProdIds(prodIds, startTime, endTime);

        Map<Long, ProdEffectRespParam> prodFlowMap = prodFlowList.stream().collect(Collectors.toMap(ProdEffectRespParam::getProdId, p -> p));
        Map<Long, ProdEffectRespParam> prodOrderMap = prodOrderList.stream().collect(Collectors.toMap(ProdEffectRespParam::getProdId, p -> p));
        Map<Long, ProdEffectRespParam> prodOrderRefundMap = prodOrderRefundList.stream().collect(Collectors.toMap(ProdEffectRespParam::getProdId, p -> p));
        Iterator<ProdEffectRespParam> iterator = respParams.iterator();
        while (iterator.hasNext()) {
            ProdEffectRespParam respParam = iterator.next();
            // 商品相关数据
            ProdEffectRespParam prodFlowParam = prodFlowMap.get(respParam.getProdId());

            //订单相关
            ProdEffectRespParam prodOrderParam = prodOrderMap.get(respParam.getProdId());

            //退款相关
            ProdEffectRespParam prodOrderRefundParam = prodOrderRefundMap.get(respParam.getProdId());

            if (Objects.isNull(prodFlowParam) && Objects.isNull(prodOrderParam) && Objects.isNull(prodOrderRefundParam)) {
                iterator.remove();
            }
        }
        Set<Long> ids = respParams.stream().map(ProdEffectRespParam::getProdId).collect(Collectors.toSet());
        if (ids.isEmpty()) {
            return pages;
        }
        if (allProd) {
            pages.setRecords(productMapper.listProdByParam(param, ids));
        } else {
            pages = productMapper.pageProdByParam(page, param, ids);
        }
        List<Long> prodIdList = pages.getRecords().stream().map(ProdEffectRespParam::getProdId).collect(Collectors.toList());
        Map<Long, ProdLang> prodLangMap = langManager.getProdLangMap(prodIdList);
        for (ProdEffectRespParam prodEffectRespParam : pages.getRecords()) {
            setDefaultValue(prodEffectRespParam);
            ProdLang prodLang = prodLangMap.get(prodEffectRespParam.getProdId());
            if (Objects.nonNull(prodLang)) {
                prodEffectRespParam.setProdName(prodLang.getProdName());
            }
            // 补充商品状态
            ProdStatusEnums prodStatusEnum = ProdStatusEnums.instance(prodEffectRespParam.getStatus());
            prodEffectRespParam.setProdStatus(Objects.isNull(prodStatusEnum) ? "" : prodStatusEnum.getDesc());
        }
        handlePages(pages, prodFlowMap, prodOrderMap, prodOrderRefundMap);
        return pages;
    }

    private void setDefaultValue(ProdEffectRespParam prodEffectRespParam){
        // 添加默认值
        prodEffectRespParam.setPrice(null == prodEffectRespParam.getPrice() ? 0.0 : prodEffectRespParam.getPrice());
        prodEffectRespParam.setExpose(null == prodEffectRespParam.getExpose() ? 0 : prodEffectRespParam.getExpose());
        prodEffectRespParam.setExposePersonNum(null == prodEffectRespParam.getExposePersonNum() ? 0 : prodEffectRespParam.getExposePersonNum());
        prodEffectRespParam.setAddCartPerson(null == prodEffectRespParam.getAddCartPerson() ? 0 : prodEffectRespParam.getAddCartPerson());
        prodEffectRespParam.setAddCart(null == prodEffectRespParam.getAddCart() ? 0 : prodEffectRespParam.getAddCart());
        prodEffectRespParam.setPlaceOrderPerson(null == prodEffectRespParam.getPlaceOrderPerson() ? 0 : prodEffectRespParam.getPlaceOrderPerson());
        prodEffectRespParam.setPayPerson(null == prodEffectRespParam.getPayPerson() ? 0 : prodEffectRespParam.getPayPerson());
        prodEffectRespParam.setSingleProdRate(null == prodEffectRespParam.getSingleProdRate() ? 0.0 : prodEffectRespParam.getSingleProdRate());
        prodEffectRespParam.setPlaceOrderNum(null == prodEffectRespParam.getPlaceOrderNum() ? 0 : prodEffectRespParam.getPlaceOrderNum());
        prodEffectRespParam.setPayNum(null == prodEffectRespParam.getPayNum() ? 0 : prodEffectRespParam.getPayNum());
        prodEffectRespParam.setPlaceOrderAmount(null == prodEffectRespParam.getPlaceOrderAmount() ? 0.0 : prodEffectRespParam.getPlaceOrderAmount());
        prodEffectRespParam.setPayAmount(null == prodEffectRespParam.getPayAmount() ? 0.0 : prodEffectRespParam.getPayAmount());
        prodEffectRespParam.setRefundNum(null == prodEffectRespParam.getRefundNum() ? 0 : prodEffectRespParam.getRefundNum());
        prodEffectRespParam.setRefundPerson(null == prodEffectRespParam.getRefundPerson() ? 0 : prodEffectRespParam.getRefundPerson());
        prodEffectRespParam.setRefundSuccessNum(null == prodEffectRespParam.getRefundSuccessNum() ? 0 : prodEffectRespParam.getRefundSuccessNum());
        prodEffectRespParam.setRefundSuccessPerson(null == prodEffectRespParam.getRefundSuccessPerson() ? 0 : prodEffectRespParam.getRefundSuccessPerson());
        prodEffectRespParam.setRefundSuccessAmount(null == prodEffectRespParam.getRefundSuccessAmount() ? 0.0 : prodEffectRespParam.getRefundSuccessAmount());
        prodEffectRespParam.setRefundSuccessRate(null == prodEffectRespParam.getRefundSuccessRate() ? 0.0 : prodEffectRespParam.getRefundSuccessRate());
    }



    private void handlePages(IPage<ProdEffectRespParam> pages, Map<Long, ProdEffectRespParam> prodFlowMap, Map<Long, ProdEffectRespParam> prodOrderMap, Map<Long, ProdEffectRespParam> prodOrderRefundMap) {
        for (ProdEffectRespParam temp : pages.getRecords()) {
            // 商品相关数据
            ProdEffectRespParam prodFlowParam = prodFlowMap.get(temp.getProdId());
            //订单相关
            ProdEffectRespParam prodOrderParam = prodOrderMap.get(temp.getProdId());
            //退款相关
            ProdEffectRespParam prodOrderRefundParam = prodOrderRefundMap.get(temp.getProdId());

            if (Objects.nonNull(prodFlowParam)) {
                // 加购件数
                temp.setAddCart(prodFlowParam.getAddCart());
                // 加购人数
                temp.setAddCartPerson(prodFlowParam.getAddCartPerson());
                // 曝光人数
                temp.setExposePersonNum(prodFlowParam.getExposePersonNum());
                // 曝光次数
                temp.setExpose(prodFlowParam.getExpose());
            }

            if (Objects.nonNull(prodOrderParam)) {
                // 商品下单人数
                temp.setPlaceOrderPerson(prodOrderParam.getPlaceOrderPerson());
                // 支付人数
                temp.setPayPerson(prodOrderParam.getPayPerson());
                // 单品转化率 = 商品付款人数/商品访客人数
                temp.setSingleProdRate(divAverage(temp.getPayPerson(), temp.getExposePersonNum(), 4));
                // 商品下单数
                temp.setPlaceOrderNum(prodOrderParam.getPlaceOrderNum());
                // 支付商品件数
                temp.setPayNum(prodOrderParam.getPayNum());
                // 商品下单金额
                temp.setPlaceOrderAmount(prodOrderParam.getPlaceOrderAmount());
                // 商品支付金额
                temp.setPayAmount(setDefaultDouble(prodOrderParam.getPayAmount()));
            }

            if (Objects.nonNull(prodOrderRefundParam)) {
                // 申请退款订单数
                temp.setRefundNum(prodOrderRefundParam.getRefundNum());
                // 申请退款人数
                temp.setRefundPerson(prodOrderRefundParam.getRefundPerson());
                // 成功退款订单数
                temp.setRefundSuccessNum(prodOrderRefundParam.getRefundSuccessNum());
                // 成功退款人数
                temp.setRefundSuccessPerson(prodOrderRefundParam.getRefundSuccessPerson());
                // 成功退款金额
                temp.setRefundSuccessAmount(prodOrderRefundParam.getRefundSuccessAmount());
                // 退款率 = 成功退款订单数/申请退款订单数
                temp.setRefundSuccessRate(divAverage(temp.getRefundSuccessNum(), temp.getRefundNum(), 4));
            }
        }

    }

    private Set<Long> getFlowProdId(Integer dateType, Date startTime, Date endTime, Long shopId) {
        Set<Long> prodIdSet = new HashSet<>();
        if (Objects.equals(1, dateType)) {
            List<FlowLog> flowLogList = flowLogService.getFlowLogListByCache();
            List<Long> prodIds = flowLogList.stream()
                    .filter(flowLog -> FlowLogPageEnum.isProdInfo(flowLog.getPageId()) && StrUtil.isNotBlank(flowLog.getBizData()))
                    .map(flowLog -> Long.valueOf(flowLog.getBizData())).toList();
            prodIdSet.addAll(prodIds);
        } else {
            List<String> prodIds = flowPageAnalysisMapper.getProdIdsByTime(startTime, endTime, shopId);
            Pattern pattern = compile("[0-9]+");
            for (String prodId : prodIds) {
                if (pattern.matcher(prodId).matches()) {
                    prodIdSet.add(Long.valueOf(prodId));
                }
            }
        }
        // 订单和退款的商品id独立获取，防止埋点数据丢失导致没有对应商品
        // 支付的商品id
        prodIdSet.addAll(orderMapper.listOrderProdIdByCreateTime(shopId, startTime, endTime));
        // 退款的商品id
        prodIdSet.addAll(orderRefundMapper.listOrderProdIdByCreateTime(shopId, startTime, endTime));

        if (CollUtil.isEmpty(prodIdSet)) {
            return null;
        }
        return prodIdSet;
    }

    private List<ProdEffectRespParam> getProdFlowData(Integer dateType, List<Long> prodIds, Date startTime, Date endTime) {
        List<ProdEffectRespParam> prodFlowList = new ArrayList<>();
        // 加购件数、加购人数、曝光人数、曝光次数、访客数
        if (Objects.equals(1, dateType)) {
            List<FlowLog> flowLogList = flowLogService.getFlowLogListByCache();
            Map<String, List<FlowLog>> flowLogMap = flowLogList.stream()
                    .filter(flowLog ->
                            (FlowLogPageEnum.isProdInfo(flowLog.getPageId()) || Objects.equals(flowLog.getVisitType(), FlowVisitEnum.SHOP_CAT.value()))
                                    && Objects.nonNull(flowLog.getBizData())
                                    && prodIds.contains(Long.valueOf(flowLog.getBizData())))
                    .collect(Collectors.groupingBy(FlowLog::getBizData));
            for (String key : flowLogMap.keySet()) {
                List<FlowLog> flowLogs = flowLogMap.get(key);
                ProdEffectRespParam prodEffectRespParam = new ProdEffectRespParam();
                int addCart = 0;
                Set<String> addCartPerson = new HashSet<>();
                int expose = 0;
                Set<String> exposePersonNum = new HashSet<>();
                for (FlowLog flowLog : flowLogs) {
                    if (Objects.equals(flowLog.getVisitType(), FlowVisitEnum.SHOP_CAT.value())) {
                        addCart = addCart + flowLog.getNums();
                        addCartPerson.add(flowLog.getUserId());
                    } else if (FlowVisitEnum.isVisitOrShare(flowLog.getVisitType())) {
                        expose++;
                        if (Objects.nonNull(flowLog.getUserId())) {
                            exposePersonNum.add(flowLog.getUserId());
                        } else {
                            exposePersonNum.add(flowLog.getUuid());
                        }
                    }
                }
                prodEffectRespParam.setProdId(Long.valueOf(key));
                //加购件数
                prodEffectRespParam.setAddCart(addCart);
                // 加购人数
                prodEffectRespParam.setAddCartPerson(addCartPerson.size());
                // 曝光人数
                prodEffectRespParam.setExposePersonNum(exposePersonNum.size());
                // 曝光次数
                prodEffectRespParam.setExpose(expose);

                prodFlowList.add(prodEffectRespParam);
            }
        } else {
            prodFlowList = flowPageAnalysisMapper.getProdEffectByDateAndProdIds(prodIds, startTime, endTime);
        }
        return prodFlowList;
    }

    @Override
    public List<ProdSingleTrendParam> getSingleProdTrend(Long prodId, ProdEffectParam param) {
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        List<DateParam> dates = DateUtils.findEveryDays(startTime, endTime);
        List<ProdSingleTrendParam> resList = new ArrayList<>();
        for (DateParam date : dates) {
            ProdSingleTrendParam res = new ProdSingleTrendParam();
            res.setCurrentDay(DateUtils.dateToStrYmd(date.getStartTime()));
            param.setStartTime(date.getStartTime());
            param.setEndTime(date.getEndTime());
            // 浏览量
            res.setBrowse(setDefaultZero(flowPageAnalysisMapper.countProdExposeNumByParam(prodId, param.getStartTime(), param.getEndTime())));
            // 访客数
            res.setVisitor(setDefaultZero(flowPageAnalysisMapper.countProdVisitorNumByProdId(prodId, param.getStartTime(), param.getEndTime())));
            // 付款人数
            res.setPayPerson(orderItemMapper.countPayPerson(prodId, param));
            // 付款商品件数
            res.setPayNum(setDefaultZero(productMapper.countPayNum(prodId, param)));
            resList.add(res);
        }
        return resList;
    }


    private Double refundRate(Integer a, Integer b) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b);
    }

    public Integer setDefaultZero(Integer data) {
        if (Objects.isNull(data)) {
            return 0;
        }
        return data;
    }

    public Long setDefaultZero(Long data) {
        if (Objects.isNull(data)) {
            return 0L;
        }
        return data;
    }

    public Double setDefaultDouble(Double data) {
        if (Objects.isNull(data)) {
            return 0.0;
        }
        return data;
    }

    private Double divAverage(Integer a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    private Double divAverage(Double a, Long b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    private Double divAverage(Double a, Double b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    @Override
    public IPage<Product> pageProducts(PageParam<Product> page, ProductParam product) {
        return productMapper.pageProducts(page, product);
    }

    @Override
    public IPage<Product> pageByLang(PageParam<Product> page, ProductParam product) {
        IPage<Product> productPage = productMapper.pageByLang(page, product);
        langManager.getProdLang(productPage.getRecords());
        loadProdStock(productPage.getRecords());
        return productPage;
    }

    @Override
    public List<Product> recoveryPreSaleProd() {
        List<Product> products = list(new LambdaUpdateWrapper<Product>().eq(Product::getPreSellStatus, 1).lt(Product::getPreSellTime, new Date()));
        if (CollectionUtils.isEmpty(products)) {
            return null;
        }
        productMapper.updatePreSale(products);
        return products;
    }

//    @Override
//    public IPage<ProductTagParam> pageByLangAndTag(PageParam<Product> page, ProductTagParam product, Integer isContain) {
//        return productMapper.pageByLangAndTag(page,product,isContain);
//    }

    @Override
    public List<Product> listProdByIdsAndType(ProductParam product) {
        List<Product> productList = productMapper.listProdByIdsAndType(product);
        langManager.getProdLang(productList);
        return productList;
    }

    @Override
    public List<Product> getProductListBySpuIds(Set<Long> prodIds) {
        if (CollectionUtil.isEmpty(prodIds)) {
            return new ArrayList<>();
        }
        List<Product> prodList = productMapper.getProductListBySpuIds(prodIds);
        langManager.getProdLang(prodList);
        return prodList;
    }

    @Override
    public IPage<Product> canDistributionProdPage(PageParam<Product> page, ProductParam product) {
        IPage<Product> productPage = productMapper.canDistributionProdPage(page, product);
        langManager.getProdLang(productPage.getRecords());
        return productPage;
    }

    @Override
    public void updateProductType(Long prodId, Integer prodType) {
        if (Objects.isNull(prodId)) {
            return;
        }
        bathUpdateProductType(Collections.singletonList(prodId), prodType);
    }

    @Override
    public void bathUpdateProductType(List<Long> prodIds, Integer prodType) {
        if (CollUtil.isEmpty(prodIds)) {
            return;
        }
        productMapper.bathUpdateProductType(prodIds, prodType);
        removeProductCacheByProdIds(prodIds);
    }

    @Override
    public Map<Long, Product> getProdDeliveryTemplateIdByProdIds(List<Long> prodIds) {
        List<Product> products = productMapper.getProdDeliveryTemplateIdByProdIds(prodIds);
        return products.stream().collect(Collectors.toMap(Product::getProdId, p -> p));
    }

    @Override
    public int getProductNum(Long shopId, Integer status) {
        return productMapper.getProductNum(shopId,status);
    }

    @Override
    public List<ProductBO> listProdStockAndSold(List<Long> prodIds) {
        if (CollUtil.isEmpty(prodIds)) {
            return new ArrayList<>();
        }
        List<ProductBO> productList = productMapper.listEsProdSoldAndStock(prodIds);
        Map<Long, SkuStockVO> stockMap = skuService.mapProdStock(prodIds);
        for (ProductBO productBO : productList) {
            SkuStockVO skuStockVO = stockMap.get(productBO.getProdId());
            productBO.setTotalStocks(skuStockVO.getStock());
            productBO.setSoldNum(skuStockVO.getSale());
        }
        return productList;
    }


    @Override
    public void changeStatusByProdIds(List<Long> pIds, Integer status) {
        productMapper.changeStatusByProdIds(pIds, status);
    }

    @Override
    public IPage<Product> prodSkuPage(PageParam<Product> page, ProductParam productParam) {
        List<Product> products = productMapper.prodSkuPage(new PageAdapter(page), productParam);
        if (!CollectionUtils.isEmpty(products)) {
            langManager.getProdLang(products);
            // 查询库存
            List<SkuStockVO> skuStockVOList = new ArrayList<>(Constant.INITIAL_CAPACITY);
            for (Product product : products) {
                for (Sku sku : product.getSkuList()) {
                    skuStockVOList.add(new SkuStockVO(sku.getSkuId()));
                }
            }
            Map<String, SkuStockVO> skuStockMap = skuStockService.listSkuStock(skuStockVOList);
            // 补充信息
            SkuStockVO skuStockVO;
            for (Product product : products) {
                for (Sku sku : product.getSkuList()) {
                    skuStockVO = skuStockMap.get(StockUtil.skuPointKey(sku.getSkuId(), null));
                    sku.setStocks(Objects.isNull(skuStockVO) ? 0 : skuStockVO.getStock());
                }
            }
        }
        page.setRecords(products);
        page.setTotal(productMapper.countProdSkuList(new PageAdapter(page), productParam));
        return page;
    }

    @Override
    public List<Product> prodAndSkuInfo(List<Long> prodIds, List<Long> skuIds) {
        List<Product> products = productMapper.prodAndSkuInfo(prodIds, skuIds);
        langManager.getProdLang(products);
        return products;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleAuditProd(Product dbProduct, OfflineHandleEvent offlineHandleEvent) {
        int handleStatus = offlineHandleEvent.getStatus();
        if (Objects.equals(handleStatus, OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            // 审核通过
            if(!Objects.equals(dbProduct.getMold(),ProdMoldEnum.COMBO.value())){
                dbProduct.setStatus(ProdStatusEnums.NORMAL.getValue());
                updateById(dbProduct);
                return;
            }
            checkEnableComboSpu(dbProduct);
        } else if (Objects.equals(handleStatus, OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue())) {
            // 审核不通过,平台下线
            offlineHandleEvent.setHandleType(OfflineHandleEventType.PROD.getValue());
            offlineHandleEvent.setHandleId(dbProduct.getProdId());
            offlineHandleEvent.setCreateTime(new Date());
            offlineHandleEvent.setShopId(dbProduct.getShopId());
            offlineHandleEvent.setStatus(handleStatus);
            offlineHandleEventService.save(offlineHandleEvent);
            productMapper.updateToOffline(dbProduct.getProdId());
        }
    }

    @Override
    public List<Product> listProdAndSku(List<Long> prodIds) {
        List<Product> products = productMapper.listProdAndSku(prodIds);
        langManager.getProdLang(products);
        List<Sku> skus = new ArrayList<>();
        for (Product product : products) {
            skus.addAll(product.getSkuList());
        }
        skuService.setSkuStock(skus);
        return products;
    }

    @Override
    public List<Product> listProdByAutidStatus() {
        List<Product> products = productMapper.selectList(new LambdaQueryWrapper<Product>().eq(Product::getStatus, ProdStatusEnums.AUDIT.getValue()));
        return products;
    }

    @Override
    public List<ProductVO> listProdWithLang(ProductDto productDto) {
        return productMapper.listProdWithLang(productDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProdStatus(List<Long> prodIds, Integer prodStatus) {
        for (Long prodId : prodIds) {
            ProductServiceImpl productService = (ProductServiceImpl) AopContext.currentProxy();
            Product dbProduct = productService.getProductByProdId(prodId);
            Product product = new Product();
            product.setProdId(prodId);
            //获取店铺信息
            ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(dbProduct.getShopId());
            // 签约期已过的店铺不能上架商品
            if (Objects.equals(prodStatus, ProdStatusEnums.NORMAL.getValue()) && !Objects.equals(shopDetail.getShopStatus(), ShopStatus.OPEN.value())) {
                // 店铺有效期已过，不能进行此操作，请联系管理员后重试
                if (shopDetail.getContractEndTime() != null && shopDetail.getContractEndTime().compareTo(new Date()) < 0) {
                    log.info("店铺有效期已过，不能进行此操作，请联系管理员后重试");
                    throw new YamiShopBindException("yami.product.shop.expired");
                }
                // 店铺处于违规下线中，不能修改商品，请联系管理员后重试
                log.info("店铺处于违规下线中，不能修改商品，请联系管理员后重试");
                throw new YamiShopBindException("yami.product.shop.offline");
            }
            // 如果开启了商品审核，要上架商品默认进入待审核状态6
            SysProdConfig sysProdConfig = sysConfigService.getSysConfigObject(Constant.PROD_SWITCH_CONFIG, SysProdConfig.class);
            if (BooleanUtil.isTrue(sysProdConfig.getProdAudit()) && Objects.equals(prodStatus, ProdStatusEnums.NORMAL.getValue())) {
                product.setStatus(ProdStatusEnums.AUDIT.getValue());
                dbProduct.setStatus(ProdStatusEnums.AUDIT.getValue());
            } else {
                product.setStatus(prodStatus);
                if (Objects.equals(prodStatus, ProdStatusEnums.NORMAL.getValue())) {
                    product.setPutawayTime(new Date());
                }
                dbProduct.setStatus(prodStatus);
            }
            product.setIsTop(0);

            // 商品状态改变时的发送事件，让活动下线
            applicationContext.publishEvent(new ProdChangeStatusEvent(dbProduct, dbProduct.getStatus()));
            applicationContext.publishEvent(new ComboEvent(dbProduct, prodStatus));

            productService.updateById(product);

            productService.removeProdCacheByProdId(prodId);
            List<String> userIds = basketService.listUserIdByProdId(prodId);
            //清除购物车缓存
            basketService.removeCacheByUserIds(userIds);
            eventPublisher.publishEvent(new EsProductUpdateEvent(product.getProdId(), null, EsOperationType.SAVE));
            // 下线关联的组合商品
            offlineRelatedComboBySpuIds(prodIds);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Product> handleExpireVirtualProd() {
        List<Product> products = list(new LambdaUpdateWrapper<Product>()
                .eq(Product::getMold, 1)
                .eq(Product::getStatus, ProdStatusEnums.NORMAL.getValue())
                .eq(Product::getWriteOffTime, 0)
                .lt(Product::getWriteOffEnd, new Date()));
        if (CollectionUtils.isEmpty(products)) {
            return null;
        }
        for (Product product : products) {
            product.setStatus(ProdStatusEnums.SHOP_OFFLINE.getValue());
            updateById(product);
            // 如果是商品下架操作
            // 商品状态改变时发送事件到活动，让活动下线
            applicationContext.publishEvent(new ProdChangeStatusEvent(product, product.getStatus()));
        }
        return products;
    }

    @Override
    public IPage<ProductVO> pageStockPointSpu(PageParam<ProductVO> pageDTO, StockPointSkuDTO spuDTO) {
        // 过滤空库存，空库存只有默认仓库会出现
        if (Objects.equals(spuDTO.getType(), 0) && Objects.equals(spuDTO.getQueryHasStock(), 1)) {
            List<Long> emptySkuIds = this.listEmptySkuIds(Collections.singletonList(spuDTO.getStockPointId()));
            if (!CollectionUtils.isEmpty(emptySkuIds)) {
                spuDTO.setNotInSkuIds(emptySkuIds);
            }
        }
        pageDTO.setRecords(productMapper.listPointSpu(pageDTO, spuDTO));
        pageDTO.setTotal(productMapper.listPointSpu(null, spuDTO).size());
        return pageDTO;
    }

    @Override
    public void intiStockPointSKu() {
        // 获取所有的默认仓库
        List<Warehouse> warehouseList = warehouseService.list(new LambdaQueryWrapper<Warehouse>()
                .eq(Warehouse::getType, 0));
        if (CollectionUtils.isEmpty(warehouseList)) {
            throw new YamiShopBindException(ResponseEnum.EXCEPTION);
        }
        // 根据店铺id和系统类型区分
        Map<String, List<Warehouse>> warehouseVOMap = warehouseList.stream().collect(Collectors.groupingBy(warehouse -> warehouse.getShopId() + Constant.UNDERLINE + warehouse.getSysType()));
        List<Sku> skuList = skuMapper.selectList(new LambdaQueryWrapper<Sku>().ne(Sku::getStatus, StatusEnum.DELETE.value()));
        List<Long> skuIds = skuList.stream().map(Sku::getSkuId).toList();
        List<StockPointSkuVO> stockPointSkuVOList = stockPointSkuService.listBySkuIds(skuIds);
        Map<Long, List<StockPointSkuVO>> stockPointSkuMap = stockPointSkuVOList.stream().collect(Collectors.groupingBy(StockPointSkuVO::getSkuId));

        List<Long> prodIds = skuList.stream().map(Sku::getProdId).collect(Collectors.toList());
        List<Product> prodList = list(new LambdaQueryWrapper<Product>().in(Product::getProdId, prodIds));
        Map<Long, Long> shopMap = prodList.stream().collect(Collectors.toMap(Product::getProdId, Product::getShopId));
        List<StockPointSkuDTO> stockPointSkuList = new ArrayList<>(prodList.size());
        for (Sku skuVO : skuList) {
            // 已经有区域库存，就不用再创建默认库存了
            if (stockPointSkuMap.containsKey(skuVO.getSkuId()) || Objects.equals(skuVO.getStatus(), StatusEnum.DELETE.value())) {
                continue;
            }
            StockPointSkuDTO stockPointSku = new StockPointSkuDTO();
            Integer sysType = SysTypeEnum.MULTISHOP.value();
            Long shopId = shopMap.get(skuVO.getProdId());
            if (shopId == null) {
                continue;
            }

            // 平台端-积分商品
            if (Objects.equals(shopId, Constant.ZERO_LONG)) {
                sysType = SysTypeEnum.PLATFORM.value();
            }
            String key = shopId + Constant.UNDERLINE + sysType;
            if (!warehouseVOMap.containsKey(key)) {
                continue;
            }
            Long warehouseId = warehouseVOMap.get(key).get(0).getWarehouseId();
            stockPointSku.setStockPointId(warehouseId);
            stockPointSku.setStockPointType(StockPointType.WAREHOUSE.getValue());
            stockPointSku.setSkuId(skuVO.getSkuId());
            stockPointSku.setProdId(skuVO.getProdId());
            stockPointSku.setType(0);
            stockPointSku.setStatus(skuVO.getStatus());
            stockPointSkuList.add(stockPointSku);
        }
        System.out.println();
        DataBatchHandleUtil.batchSplitInsert(stockPointSkuList, stockPointSkuService::batchSave);
    }

    @Override
    public void loadProdStock(List<Product> prodList) {
        if (CollUtil.isEmpty(prodList)) {
            return;
        }
        List<Long> prodIds = prodList.stream().map(Product::getProdId).toList();
        Map<Long, SkuStockVO> skuStockMap = skuService.mapProdStock(prodIds);
        for (Product product : prodList) {
            SkuStockVO skuStockVO = skuStockMap.get(product.getProdId());
            product.setTotalStocks(skuStockVO.getStock());
            product.setSoldNum(skuStockVO.getSale());
        }
    }

    @Override
    public List<ProductDto> queryListByUpdateTime(String beginTime, String overTime) {
        return productMapper.selectListByUpdateTime(beginTime,overTime);
    }

    @Override
    public Page<Product> getZeroPage(Page page) {
        return productMapper.getZeroPage(page);
    }
    @Override
    public Page<Product> noZeroPage(Page page) {
        return productMapper.noZeroPage(page);
    }
    @Override
    public void addZero(Long[] ids) {
        productMapper.addZero(ids);
    }
    @Override
    public void deleteZero(Long[] ids) {
        productMapper.deleteZero(ids);
    }

    /**
     * 组合商品上架条件:
     * 1.关联商品 > 0
     * 2.关联商品不为(预售类型
     * 3.关联的商品(sku)都为上架状态
     * @param productDb
     */
    private void checkEnableComboSpu(Product productDb) {
        Integer status = ProdStatusEnums.NORMAL.getValue();
        // 这里不需要供应商发货的条件判断,因为代销组合商品只能供应商发货
        List<Sku> skuList = skuService.listSkuByProdId(productDb.getProdId());
        skuList = skuList.stream().filter(sku -> Objects.equals(sku.getStatus(), StatusEnum.ENABLE.value())).toList();
        List<SkuComboVO> combSpus = skuComboService.listCombProdByProdIds(Collections.singletonList(productDb.getProdId()));
        Map<Long, List<SkuComboVO>> skuComboMap = combSpus.stream().collect(Collectors.groupingBy(SkuComboVO::getSkuId));
        for (Sku skuVO : skuList) {
            if (!skuComboMap.containsKey(skuVO.getSkuId())) {
                status = ProdStatusEnums.SHOP_OFFLINE.getValue();
                break;
            }
        }
        Set<Long> prodIds = combSpus.stream().map(SkuComboVO::getComboProdId).collect(Collectors.toSet());
        Set<Long> skuIds = combSpus.stream().map(SkuComboVO::getComboSkuId).collect(Collectors.toSet());
        long count = count(new LambdaQueryWrapper<Product>().in(Product::getProdId,prodIds)
                .and(wrapper -> wrapper.eq(Product::getPreSellStatus,1).or().ne(Product::getStatus, 1)));
        long skuCount = skuService.count(new LambdaQueryWrapper<Sku>().in(Sku::getSkuId,skuIds).ne(Sku::getStatus, 1));
        if(count > 0 || skuCount > 0){
            status = ProdStatusEnums.SHOP_OFFLINE.getValue();
        }
        productDb.setStatus(status);
        updateById(productDb);
    }

    /**
     * 获取空库存的skuId集合
     * @param warehouseIds 仓库id集合
     * @return 空库存skuId集合
     */
    private List<Long> listEmptySkuIds(List<Long> warehouseIds) {
        // 查询仓库关联的所有sku库存
        Map<String, SkuStockVO> stockMap = stockManager.mapSkuStockByStockPointIds(warehouseIds);
        if (stockMap.size() == 0) {
            return new ArrayList<>();
        }
        // 找出库存为0的skuId, 通过'not in'，分页查询sku对应的spu
        return stockMap.values().stream()
                .filter(x -> x.getStock() <= 0)
                .map(SkuStockVO::getSkuId).toList();
    }

    private void stockBillLogChange(Product product, List<Sku> insertSkuList, List<Sku> addStockSkuList, List<Sku> reduceStockSkuList) {
        Integer sysType = SysTypeEnum.MULTISHOP.value();
        String mobile = product.getEmployeeMobile();
        Long employeeId = product.getEmployeeId();
        Long shopId = product.getShopId();
        // 记录普通商品通过编辑改变的库存记录
        if (CollUtil.isNotEmpty(insertSkuList)) {
            // 记录新增的sku库存初始化
            List<StockPointSkuDTO> stockPointSkuDTOList = new ArrayList<>();
            for (Sku sku : insertSkuList) {
                stockPointSkuDTOList.addAll(sku.getStockPointList());
            }
            skuStockService.addBillLogList(employeeId, mobile, sysType, StockBillType.INITIALIZE.value(), StockType.WAREHOUSING.value(), stockPointSkuDTOList, insertSkuList, shopId, null);
        }
        if (CollUtil.isNotEmpty(addStockSkuList)) {
            // 记录库存编辑增加记录
            List<StockPointSkuDTO> stockPointSkuDTOList = new ArrayList<>();
            for (Sku sku : addStockSkuList) {
                for (StockPointSkuDTO stockPointSkuDTO : sku.getStockPointList()) {
                    stockPointSkuDTO.setStock(stockPointSkuDTO.getChangeStock() != null ? stockPointSkuDTO.getChangeStock() : stockPointSkuDTO.getStock());
                    stockPointSkuDTO.setSkuId(sku.getSkuId());
                }
                stockPointSkuDTOList.addAll(sku.getStockPointList());
            }
            skuStockService.addBillLogList(employeeId, mobile, sysType, StockBillType.EDIT_STORAGE.value(), StockType.WAREHOUSING.value(), stockPointSkuDTOList, addStockSkuList, shopId, null);
        }
        if (CollUtil.isNotEmpty(reduceStockSkuList)) {
            // 记录库存编辑减少记录
            List<StockPointSkuDTO> stockPointSkuDTOList = new ArrayList<>();
            for (Sku sku : reduceStockSkuList) {
                sku.getStockPointList().forEach(s-> s.setStock(s.getChangeStock() * -1));
                stockPointSkuDTOList.addAll(sku.getStockPointList());
            }
            skuStockService.addBillLogList(employeeId, mobile, sysType, StockBillType.EDIT_OUTBOUND.value(), StockType.OUT_OF_STOCK.value(), stockPointSkuDTOList, reduceStockSkuList, shopId, null);
        }
    }

    private void cannotEdit(Product dbProduct) {
        if (Objects.isNull(dbProduct.getProdType())) {
            return;
        }
        if (dbProduct.getProdType().equals(ProdType.PROD_TYPE_GROUP.value())) {
            // 商品正在参与拼团活动，无法修改规格
            throw new YamiShopBindException("yami.product.join.group");
        }
        if (dbProduct.getProdType().equals(ProdType.PROD_TYPE_SECKILL.value())) {
            // 商品正在参与秒杀活动，无法修改规格
            throw new YamiShopBindException("yami.product.join.seckill");
        }
    }



    private void setSkuName(List<ProdLangParam> prodLangList, List<Sku> skuList) {
        Map<Integer, String> prodNameMap = prodLangList.stream().collect(Collectors.toMap(ProdLangParam::getLang, ProdLangParam::getProdName));
        for (Sku sku : skuList) {
            for (SkuLang skuLang : sku.getSkuLangList()) {
                String prodName = prodNameMap.get(skuLang.getLang());
                if (StrUtil.isBlank(prodName)) {
                    continue;
                }
                if (StrUtil.isBlank(skuLang.getSkuName())) {
                    skuLang.setProdName(prodName);
                } else {
                    skuLang.setProdName(prodName + " " + skuLang.getSkuName());
                }
            }
        }
    }

    private void checkProdLang(List<ProdLangParam> prodLangList) {
        Integer lang = langManager.getDefaultLang();
        if (CollUtil.isEmpty(prodLangList)) {
            throw new YamiShopBindException("yami.product.exception.prodLangNull");
        }
        boolean containsMaster = false;
        for (ProdLangParam prodLangParam : prodLangList) {
            if (Objects.equals(prodLangParam.getLang(), lang)) {
                containsMaster = true;
            }
            prodLangParam.setProdName(prodLangParam.getProdName().trim());
            if (StrUtil.isNotBlank(prodLangParam.getBrief())) {
                prodLangParam.setBrief(prodLangParam.getBrief().trim());
            }
        }
        if (!containsMaster) {
            throw new YamiShopBindException("yami.product.exception.prodLangUpdate");
        }
    }


    private void saveLang(ProductParam productParam) {
        List<ProdLang> prodLangList = BeanUtil.mapAsList(productParam.getProdLangList(), ProdLang.class);
        for (ProdLang prodLang : prodLangList) {
            prodLang.setProdId(productParam.getProdId());
        }
        prodLangService.saveBatch(prodLangList);
    }

    private boolean updateProdSku(Product dbProduct, Product product, List<Long> dbSkuIds, Map<Long, Sku> dbSkuMap, List<Sku> skuList, boolean skuStatusChangeFlag, List<Sku> insertSkuList, List<Sku> addStockSkuList, List<Sku> reduceStockSkuList) {
//        Integer totalStock = 0;
        // 如果是活动商品不能删除sku，还需要判断下是否删除了
        if(skuList.size() < dbSkuIds.size()){
            cannotEdit(dbProduct);
        }
        Long shopId = product.getShopId();
        Integer sysType = SysTypeEnum.MULTISHOP.value();
        // 平台端-积分商品
        if (Objects.equals(shopId, Constant.ZERO_LONG)) {
            sysType = SysTypeEnum.PLATFORM.value();
        }
        List<SkuStockVO> skuStockList = new ArrayList<>(skuList.size());
        List<Sku> updateSkuList = new ArrayList<>();
        // 更新的sku数量
        int updateSkuCount = 0;
        Sku addSkuDTO = new Sku();
        Sku reduceSkuDTO = new Sku();
        for (Sku sku : skuList) {
            sku.setIsDelete(0);
//            if (Objects.equals(sku.getStatus(), 1)) {
//                totalStock += sku.getStocks();
//            }
            // 如果数据库中原有sku就更新，否者就插入
            if (dbSkuIds.contains(sku.getSkuId())) {
                Sku dbSku = dbSkuMap.get(sku.getSkuId());
                if (!skuStatusChangeFlag) {
                    skuStatusChangeFlag = !Objects.equals(dbSku.getStatus(), sku.getStatus());
                }
                skuService.updateSku(sku,product.getMold());
                List<StockPointSkuDTO> addStockPointList = new ArrayList<>();
                List<StockPointSkuDTO> reduceStockPointList = new ArrayList<>();
                for (StockPointSkuDTO pointSkuDTO : sku.getStockPointList()) {
                    if ((Objects.isNull(pointSkuDTO.getChangeStock()) && Objects.isNull(pointSkuDTO.getStockPointSkuId()))
                            || (Objects.nonNull(pointSkuDTO.getChangeStock()) && pointSkuDTO.getChangeStock() > 0)) {
                        // 库存增加
                        addStockPointList.add(pointSkuDTO);
                    }
                    if (Objects.nonNull(pointSkuDTO.getChangeStock()) && pointSkuDTO.getChangeStock() < 0) {
                        // 库存减少
                        reduceStockPointList.add(pointSkuDTO);
                    }
                }
                // 判断一下之前的库存点数据是否被删除了
                Map<Long, StockPointSkuDTO> stockPointMap = sku.getStockPointList().stream().filter(point-> Objects.nonNull(point.getStockPointSkuId())).collect(Collectors.toMap(StockPointSkuDTO::getStockPointSkuId, s->s));
                if (!org.springframework.util.CollectionUtils.isEmpty(dbSkuMap.get(sku.getSkuId()).getStockPointList())) {
                    for (StockPointSkuDTO stockPointDb : dbSkuMap.get(sku.getSkuId()).getStockPointList()) {
                        if (!stockPointMap.containsKey(stockPointDb.getStockPointSkuId())) {
                            // 库存减少
                            stockPointDb.setChangeStock(-1 * stockPointDb.getStock());
                            reduceStockPointList.add(stockPointDb);
                        }
                    }
                }
                if (Objects.nonNull(sku.getChangeStock())) {
                    if (!addStockPointList.isEmpty()) {
                        addSkuDTO = BeanUtil.map(sku, Sku.class);
                        addSkuDTO.setStockPointList(addStockPointList);
                        addStockSkuList.add(addSkuDTO);
                    }
                    if (!reduceStockPointList.isEmpty()) {
                        reduceSkuDTO = BeanUtil.map(sku, Sku.class);
                        reduceSkuDTO.setStockPointList(reduceStockPointList);
                        reduceStockSkuList.add(reduceSkuDTO);
                    }
                    updateSkuList.add(sku);
                    ++updateSkuCount;
                }
            } else {
                insertSkuList.add(sku);
            }
        }
        if (updateSkuCount != dbProduct.getSkuList().size() || skuStatusChangeFlag || CollUtil.isNotEmpty(insertSkuList)) {
            // sku规格发生 增加/删除/启用/禁用
            cannotEdit(dbProduct);
        }
//        product.setTotalStocks(totalStock);
        // 批量插入sku
        if (CollectionUtil.isNotEmpty(insertSkuList)) {
            for (Sku sku : skuList) {
                sku.setProdId(product.getProdId());
            }
            skuStockList.addAll(skuService.insertBatchAndLang(insertSkuList, shopId, product.getMold(), product.getStatus(), product.getEmployeeMobile(), product.getEmployeeId()));
        }
        if (CollectionUtil.isNotEmpty(updateSkuList)) {
            WarehouseVO warehouse = warehouseService.getDefaultWarehouseByShopId(shopId, sysType);
            if(Objects.isNull(warehouse)) {
                throw new YamiShopBindException("yami.product.exception.notDefaultWarehouse");
            }
            List<StockPointSkuDTO> stockPointS = new ArrayList<>(Constant.INITIAL_CAPACITY);
            for (Sku sku : updateSkuList) {
                skuService.addStockPoint(product.getMold(), stockPointS, product.getProdId(), product.getStatus(), skuStockList, sku, warehouse.getWarehouseId());
            }
            if (CollUtil.isNotEmpty(stockPointS)) {
                stockPointSkuService.changeStockPoint(stockPointS, false);
            }
        }
        Product.DeliveryModeVO deliveryModeVO = Json.parseObject(product.getDeliveryMode(), Product.DeliveryModeVO.class);

        if (!Objects.equals(product.getMold(), ProdMoldEnum.COMBO.value()) && shopId != Constant.PLATFORM_SHOP_ID) {
            // 添加出入库记录
            stockBillLogChange(product, null, addStockSkuList, reduceStockSkuList);
        }

        // 判断处理库存
        skuStockService.handSkuStock(product.getProdId(), skuStockList, LuaOperateEnum.SKU_REPLACE, deliveryModeVO.getHasUserPickUp(), product.getShopId());

        // 处理库存预警
        skuService.batchUpdateSkuWarning(skuList);
        return skuStatusChangeFlag;
    }
    /**
     * 组合商品关联的子商品状态变更,导致组合商品下架:
     * 1.关联子商品信息不变
     * 1.1 子商品下架
     * 1.2 子商品由商家发货转为供应商发货(商家商品)
     * 1.3 子商品变成预售商品
     * 1.4 sku禁用
     * 2.关联子商品信息删除
     * 2.1 删除子商品或者规格
     *
     * @param productParam
     * @param spuDb
     * @param saveProd
     */
    private void checkComboSpuOrRelatedCombo(ProductParam productParam, Product spuDb, boolean saveProd) {
        if(!Objects.equals(productParam.getMold(), ProdMoldEnum.COMBO.value())) {
            // 如果是新增的普通商品不需要判断
            if(saveProd){
                return;
            }
            Set<Long> handleSkuIds = new HashSet<>();
            Set<Long> deleteSkuIds = new HashSet<>();
            List<SkuAdminDTO> skuList = productParam.getSkuList().stream().filter(skuDTO -> Objects.nonNull(skuDTO.getSkuId())).toList();
            Map<Long, SkuAdminDTO> skuMap = skuList.stream().collect(Collectors.toMap(SkuAdminDTO::getSkuId, skuVO -> skuVO));
            Set<Long> skuIds = skuList.stream().map(SkuAdminDTO::getSkuId).collect(Collectors.toSet());
            // 开启预售需要下架关联的子商品下架
            if(Objects.nonNull(productParam.getPreSellTime())) {
                handleSkuIds.addAll(skuIds);
            }
            // 获取修改前的sku信息
            List<Sku> oldSkuList = skuService.listSkuByProdId(productParam.getProdId());
            Map<Long, Sku> skuDbMap = oldSkuList.stream().collect(Collectors.toMap(Sku::getSkuId, skuVO -> skuVO));
            for (Long skuIdDb : skuDbMap.keySet()) {
                // 修改时如果不存在数据库的sku,则表示已经删除,进行下架和删除关联
                if(!skuMap.containsKey(skuIdDb)){
                    deleteSkuIds.add(skuIdDb);
                    continue;
                }
                // 如果数据库是启用,修改时变成禁用,则进行下架
                if(Objects.equals(skuDbMap.get(skuIdDb).getStatus(),StatusEnum.ENABLE.value()) && Objects.equals(skuMap.get(skuIdDb).getStatus(),StatusEnum.DISABLE.value())){
                    handleSkuIds.add(skuIdDb);
                }
            }
            handleSkuIds.addAll(deleteSkuIds);
            if(CollectionUtil.isNotEmpty(handleSkuIds)) {
                // 下架关联的组合商品
                List<Long> prodIds = skuComboService.getCombSpusByComboSpuIds(null, new ArrayList<>(handleSkuIds));
                if (CollUtil.isNotEmpty(prodIds)) {
                    updateProdStatus(prodIds,ProdStatusEnums.SHOP_OFFLINE.getValue());
                }
            }
            if(CollectionUtil.isNotEmpty(deleteSkuIds)) {
                // 删除关联的组合商品信息
                skuComboService.deleteByComboSkuIds(deleteSkuIds.stream().toList());
            }
        }
        if(!Objects.equals(productParam.getMold(), ProdMoldEnum.COMBO.value())) {
            return;
        }
        // 组合商品不能选择其他组合商品一起组合
        Set<Long> prodIds = new HashSet<>();
        for (SkuAdminDTO skuDTO : productParam.getSkuList()) {
            prodIds.addAll(skuDTO.getSkuComboList().stream().map(SkuComboDTO::getComboProdId).collect(Collectors.toSet()));
        }
        List<Product> spuList = listProdAndSku(prodIds.stream().toList());
        List<Product> comboSpuList = spuList.stream().filter(spuVO -> Objects.equals(spuVO.getMold(), ProdMoldEnum.COMBO.value())).toList();
        for (Product spuVO : spuList) {
            if (Objects.equals(spuVO.getMold(), ProdMoldEnum.COMBO.value())) {
                throw new YamiShopBindException("yami.product.exception.comboProdCannotCombo");
            }
            // 组合商品不能为预售类型
            if (Objects.equals(spuVO.getPreSellStatus(),1)) {
                throw new YamiShopBindException("yami.product.exception.comboProdCannotPresale");
            }
        }
        // 判断一下是否为全实物商品,用于赠品操作
        List<Product> noRealSpuList = spuList.stream().filter(spuVO -> !Objects.equals(spuVO.getMold(), ProdMoldEnum.REAL.value())).toList();
        productParam.setIsAllEntity(CollectionUtil.isNotEmpty(noRealSpuList) ? 0 : 1);
    }

    private void offlineRelatedComboBySpuIds(List<Long> prodIds) {
        // 下架关联的组合商品
        List<Long> comboSpuIds = skuComboService.getCombSpusByComboSpuIds(prodIds,null);
        if(CollUtil.isEmpty(comboSpuIds)){
            return;
        }
        updateProdStatus(comboSpuIds,StatusEnum.DISABLE.value());
    }

}
